home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 July: Mac OS SDK / Dev.CD Jul 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw 3D / Samples / SampleCode / QD3D Pascal Demos / SimpleViewer Pascal ƒ / SimpleViewer.p < prev    next >
Encoding:
Text File  |  1996-11-15  |  21.7 KB  |  824 lines  |  [TEXT/CWIE]

  1. Program SimpleViewer;
  2. {--------------------------------------------------------------------------------------------
  3. // simple viewer application 
  4. // DEVELOPER SUPPORT May 95
  5. //
  6. // This is a simple viewer application, that illustrates a minimal, but
  7. // functionally complete viewer application.
  8. //
  9. // Nick Thompson, Developer Support, Apple Computer (DEVSUPPORT),
  10. // ©1995, Apple Computer Inc., All Rights Reserved
  11. }
  12.  
  13. Uses
  14.     Windows, Fonts, Dialogs, Processes, ToolUtils, Devices, StandardFile, AppleEvents, 
  15.     GestaltEqu, SegLoad, Scrap, DiskInit,
  16.     QDOffscreen, QD3DViewer, QD3D, QD3DMath, QD3DDrawContext, 
  17.     QD3DShader, QD3DTransform, QD3DGroup, QD3DStyle, QD3DView;
  18.  
  19. Const
  20.     kWindowWidth    =    220;
  21.     kWindowHeight     =     150;
  22.     
  23.     mApple            =    128;
  24.     mFile            =    129;
  25.     mEdit            =    130;
  26.     
  27.     iAbout            =    1;
  28.     
  29.     iNew            =    1;
  30.     iOpen            =    2;
  31.     iUnused1        =    3;
  32.     iClose            =    4;
  33.     iSave            =    5;
  34.     iSaveAs            =    6;
  35.     iRevert            =    7;
  36.     iUnused2        =    8;
  37.     iQuit            =    9;
  38.     
  39.     iUndo            =    1;
  40.     iUnused3        =    2;
  41.     iCut            =    3;
  42.     iCopy            =    4;
  43.     iPaste            =    5;
  44.     iClear            =    6;
  45.     
  46. Var
  47.     gQuitFlag:        boolean;
  48.     gStaggerPos:    Point;
  49.     gSelfAddress:    AEAddressDesc;
  50.     gSelfPSN:        ProcessSerialNumber;
  51.     kRGBBlack:        RGBColor;
  52.     kRGBWhite:        RGBColor;
  53.  
  54. Const
  55.     kmyAboutDialogID    =    128;
  56.     kmyFatalDialogID    =    129;
  57.     kQD3DAlertID        =    27309;
  58.     
  59. Type
  60.     ViewerData    =    record
  61.         theViewer:        TQ3ViewerObject;
  62.         theFile:        FSSPec;
  63.         isFileValid:    boolean;
  64.         end;
  65.     ViewerDataPtr = ^ViewerData;
  66.     ViewerDataHandle = ^ViewerDataPtr;
  67.  
  68. Function HiWrd (alongint: longint): Integer;
  69.  
  70.     begin
  71.     HiWrd := Point(alongint).v;
  72.     end;
  73.  
  74. Function LoWrd (alongint: longint): Integer;
  75.  
  76.     begin
  77.     LoWrd := Point(alongint).h;
  78.     end;
  79.     
  80. Function SupportsQuickDraw3D: boolean;
  81.  
  82. Var
  83.     err:        OSErr;
  84.     response:    longint;
  85.     
  86.     begin
  87.     err := Gestalt(gestaltQD3D,response);
  88.     if err = NoErr then
  89.         SupportsQuickDraw3D := (response > 0) and 
  90.             (BSL(response,gestaltQD3DAvailable) > 0)
  91.     else
  92.         SupportsQuickDraw3D := false;
  93.     end;
  94.  
  95. Function SupportsQuickDraw3DViewer: boolean;
  96.  
  97. Var
  98.     err:        OSErr;
  99.     response:    longint;
  100.         
  101.     begin
  102.     err := Gestalt(gestaltQD3DViewer,response);
  103.     if err = NoErr then
  104.         SupportsQuickDraw3DViewer := (response > 0) and 
  105.             (BSL(response,gestaltQD3DViewerAvailable) > 0)
  106.     else
  107.         SupportsQuickDraw3DViewer := false;
  108.     end;
  109.  
  110. Procedure FailIfErr(something: OSErr);
  111.  
  112. Var 
  113.     theProc:    ModalFilterUPP;
  114.     theDialog:    DialogPtr; 
  115.     itemHit:    integer;
  116.     theError:    Str255;
  117.     
  118.     begin 
  119.     if something <> noErr then
  120.         begin 
  121.         NumToString(something,theError);
  122.         theDialog := GetNewDialog(kMyFatalDialogID, nil, WindowPtr(-1));
  123.         { these two lil' snappers are system 7 only }
  124.         { so if you use them, check before!! }
  125.         { in this app we will only run on Power }
  126.         { Macintosh, so we don't check }
  127.         if GetStdFilterProc(theProc) = noErr then;
  128.         if SetDialogDefaultItem(theDialog, ok) = noErr then;
  129.         ParamText( theError, '', '', '') ;
  130.         { put the dialog up and loop til}
  131.         { the user hits the OK button }
  132.         repeat
  133.             ModalDialog(theProc,itemHit);
  134.         until itemHit = ok;
  135.         DisposeDialog(theDialog);
  136.         ExitToShell; 
  137.         end;
  138.     end; 
  139.  
  140. Procedure HandleActivateWindow(theWindow: WindowPtr; activate: integer);
  141.  
  142.     begin
  143.     if theWindow <> NIL then
  144.         begin
  145.         if activate <> 0 then
  146.             begin
  147.             if LoadScrap = noErr then;
  148.             end
  149.         else     
  150.             if UnloadScrap = noErr then;
  151.         end;
  152.     end;
  153.  
  154. Procedure HandleAboutApp;
  155.  
  156. Var
  157.     theProc:    ModalFilterUPP;
  158.     theDialog:    DialogPtr;
  159.     itemHit:    integer;
  160.  
  161.     begin
  162.     theDialog := GetNewDialog(kMyAboutDialogID, nil, WindowPtr(-1));
  163.     { these two lil' snappers are system 7 only }
  164.     { so if you use them, check before!!  }
  165.     { in this app we will only run on Power }
  166.     { Macintosh, so we don't check }
  167.     if GetStdFilterProc(theProc) = noErr then;
  168.     if SetDialogDefaultItem(theDialog, ok) = noErr then;
  169.     { put the dialog up and loop til }
  170.     { the user hits the OK button }
  171.     repeat
  172.         ModalDialog(theProc,itemHit);
  173.     until itemHit = ok;
  174.     DisposeDialog(theDialog);
  175.     end;
  176.  
  177. Procedure MyAdjustMenus;
  178.  
  179. Var
  180.     theWindow:        WindowPtr;
  181.     myData:            ViewerDataHandle;
  182.     theMenu:        MenuHandle;
  183.  
  184.     begin
  185.     theWindow := FrontWindow;
  186.     if theWindow <> nil then
  187.         begin
  188.         theMenu :=  GetMenuHandle(mFile);
  189.         EnableItem(theMenu,iClose);
  190.         EnableItem(theMenu,iSaveAs);
  191.         myData := ViewerDataHandle(GetWRefCon(theWindow));
  192.          if myData^^.isFileValid then
  193.              begin
  194.             EnableItem(theMenu,iSave);
  195.             EnableItem(theMenu,iRevert);
  196.              end
  197.          else 
  198.              begin
  199.             DisableItem(theMenu,iSave);
  200.             DisableItem(theMenu,iRevert);
  201.              end;
  202.           EnableItem(GetMenuHandle(mEdit),0);
  203.         end
  204.     else 
  205.         begin
  206.         theMenu := GetMenuHandle(mFile);
  207.         DisableItem(theMenu, iClose);
  208.         DisableItem(theMenu, iRevert);
  209.         DisableItem(theMenu, iSave);
  210.         DisableItem(theMenu, iSaveAs);
  211.         DisableItem(GetMenuHandle(mEdit), 0);
  212.         end;
  213.     { we dont support undo }
  214.     DisableItem(GetMenuHandle(mEdit), iUndo);
  215.     DrawMenuBar;
  216.     end;
  217.  
  218. Function MyDisposeViewerWindow(theWindow: WindowPtr): OSErr;
  219.  
  220. Var
  221.     theViewer:        TQ3ViewerObject;
  222.     myData:            ViewerDataHandle;
  223.     
  224.     begin
  225.     if theWindow = nil then
  226.         begin
  227.         MyDisposeViewerWindow := paramErr;
  228.         exit(MyDisposeViewerWindow);
  229.         end;
  230.     myData := ViewerDataHandle(GetWRefCon(theWindow));
  231.     theViewer := myData^^.theViewer;
  232.     DisposeHandle(Handle(myData));
  233.     DisposeWindow(theWindow);
  234.     MyAdjustMenus;
  235.     MyDisposeViewerWindow := Q3ViewerDispose(theViewer);
  236.     end;
  237.  
  238. Function MyCreateViewerWindow: CGrafPtr;
  239.  
  240. Var
  241.     theRect:        Rect;
  242.     savedPort:        GrafPtr;
  243.     myViewerObj:    TQ3ViewerObject;
  244.     theWindow:        WindowPtr;
  245.     myData:            ViewerDataHandle;
  246.     
  247.     begin
  248.     myData := ViewerDataHandle(NewHandle(sizeof(ViewerData)));
  249.     GetPort(savedPort);
  250.     { set the new rect up with a stagger for multiple windows }
  251.     SetRect(theRect, gStaggerPos.h, gStaggerPos.v, gStaggerPos.h + kWindowWidth, 
  252.         gStaggerPos.v + kWindowHeight);
  253.     gStaggerPos.h := gStaggerPos.h + 16;
  254.     gStaggerPos.v := gStaggerPos.v + 16; { this is not "real staggering code, it dont wrap }    
  255.     theWindow := NewCWindow(nil, theRect, 'Untitled', false, documentProc, WindowPtr(-1), 
  256.         true, 0);    
  257.     SetPort(GrafPtr(theWindow));
  258.     { set up the viewer object here }
  259.     myViewerObj := Q3ViewerNew(CGrafPtr(theWindow), theWindow^.portRect, kQ3ViewerDefault); 
  260.     { stuff the reference to the viewer in the RefCon field of the Window }
  261.     myData^^.theViewer := myViewerObj;
  262.     myData^^.isFileValid := false;
  263.     SetWRefCon(theWindow, longint(myData));
  264.     { make sure it is visible }
  265.     ShowWindow(theWindow);
  266.     { invalidate the content region of the window -  }
  267.     { we dont do any drawing to it here. }
  268.     InvalRect (theRect);
  269.     SetPort(savedPort);
  270.     MyCreateViewerWindow := CGrafPtr(theWindow);
  271.     end;
  272.  
  273. Function HandleOpenDoc(theFile: FSSpec): OSErr;
  274.  
  275. Var
  276.     err:        OSErr;
  277.     theRef:        integer;
  278.     myData:        ViewerDataHandle;
  279.     theViewer:    TQ3ViewerObject;
  280.     theWindow:    WindowPtr;
  281.  
  282.     begin
  283.     theWindow := WindowPtr(MyCreateViewerWindow);
  284.     { open the file }
  285.     err := FSpOpenDF(theFile,fsRdPerm,theRef);
  286.     if err = noErr then
  287.         begin
  288.         myData := ViewerDataHandle(GetWRefCon(theWindow));
  289.         theViewer := myData^^.theViewer;
  290.         myData^^.theFile := theFile;
  291.         myData^^.isFileValid := true ;
  292.         if Q3ViewerUseFile(theViewer, theRef) = noErr then ;
  293.         err := FSClose(theRef) ;
  294.         end;
  295.     { set the window title }
  296.     SetWTitle(theWindow, theFile.name);
  297.     MyAdjustMenus;
  298.     HandleOpenDoc := err;
  299.     end;
  300.  
  301. Function SupportsAEVT: Boolean;
  302.  
  303. Var
  304.     err:        OSErr;
  305.     response:    longint;
  306.         
  307.     begin
  308.     err := Gestalt(gestaltAppleEventsAttr,response);
  309.     if err = noErr then
  310.         SupportsAEVT := (response > 0) and
  311.             (BSL(response,gestaltAppleEventsPresent) > 0)
  312.     else
  313.         SupportsAEVT := false;
  314.     end;
  315.  
  316. Function MyAEHandleOAPP(var theAppleEvent, reply: AppleEvent; refCon: longint): OSErr;
  317.  
  318. { we don't actually do anything on open - you could, }
  319. { for example you might want to open a blank untitled  }
  320. { window }
  321.  
  322. Var
  323.     err:    OSErr;
  324.     
  325.     begin
  326.     err := noErr ;
  327.     MyAEHandleOAPP := err;
  328.     end;
  329.  
  330. Function MyAEHandleODOC(var theAppleEvent, reply: AppleEvent; refCon: longint): OSErr;
  331.  
  332. Var
  333.     myFSS:            FSSpec;
  334.     docList:        AEDescList;
  335.     err,ignoreErr:    OSErr;
  336.     index:            longint;
  337.     itemsInList:    longint;
  338.     actualSize:        Size;
  339.     keywd:            AEKeyword;
  340.     returnedType:    DescType;
  341.     fndrInfo:        FInfo;
  342.  
  343.     begin
  344.     err := AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,docList);
  345.     if err = noErr then
  346.         begin 
  347.         { see how many descriptor items are in the list }
  348.         { this is the number of documents we want to open }
  349.         err := AECountItems(docList,itemsInList);
  350.         { now get each descriptor record from the list }
  351.         { coerce the returned data to an FSSpec record, and }
  352.         { open the asoociated file }
  353.         for index := 1 to itemsInList do
  354.             begin
  355.             err := AEGetNthPtr(docList, index, typeFSS, keywd, returnedType,
  356.                 @myFSS, sizeof(myFSS), actualSize);
  357.             if err <> NoErr then
  358.                 leave;
  359.             { we now have a valid FSSpec to reference the file, we need to know  }
  360.             { what type the file is to determine which file open function to call }
  361.             { we can determine this from the finder info for the file }
  362.             err := FSpGetFInfo(myFSS, fndrInfo);    
  363.             if err <> NoErr then
  364.                 leave;
  365.             { if we got that ok, then we check on the file   }
  366.             { type (we dont care about the creator type) }    
  367.             if (fndrInfo.fdType = 'TEXT') or (fndrInfo.fdType = '3DMF') then
  368.                 err :=  HandleOpenDoc(myFSS);
  369.             if err <> NoErr then
  370.                 leave;
  371.             end;
  372.         ignoreErr := AEDisposeDesc(docList);
  373.         end;
  374.     MyAEHandleODOC := err;
  375.     end;
  376.  
  377. Function MyAEHandlePDOC(var theAppleEvent, reply: AppleEvent; refCon: longint): OSErr;
  378.  
  379. Var
  380.     myFSS:            FSSpec;
  381.     docList:        AEDescList;
  382.     err:            OSErr;
  383.     index:            longint;
  384.     itemsInList:    longint;
  385.     actualSize:        Size;
  386.     keywd:            AEKeyword;
  387.     returnedType:    DescType;
  388.  
  389.     begin
  390.     err := AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,docList);
  391.     if err <> NoErr then
  392.         begin
  393.         MyAEHandlePDOC := err;
  394.         exit(MyAEHandlePDOC);
  395.         end;
  396.     { see how many descriptor items are in the list }
  397.     { this is the number of documents we want to open }
  398.     err := AECountItems(docList,itemsInList);
  399.     { now get each descriptor record from the list }
  400.     { coerce the returned data to an FSSpec record, and }
  401.     { open the asoociated file }
  402.     for index := 1 to itemsInList do
  403.         begin
  404.         err := AEGetNthPtr(docList, index, typeFSS, keywd, returnedType,
  405.             @myFSS, sizeof(myFSS), actualSize);
  406.         if err <> NoErr then
  407.             leave;
  408.         { err := HandlePrintDoc( &myFSS ); }
  409.         err := errAEEventNotHandled;         { we don't do this yet... }
  410.         err := AEDisposeDesc(docList);
  411.         end;
  412.     MyAEHandlePDOC := err;
  413.     end;
  414.  
  415. Function MyAEHandleQUIT(var theAppleEvent, reply: AppleEvent; refCon: longint): OSErr;
  416.  
  417. Var
  418.     err:        OSErr;
  419.     theWindow:    WindowPtr;
  420.     quitting:    Boolean;
  421.  
  422.     begin
  423.     err := noErr;
  424.     quitting := true;    
  425.     { attempt to close all documents }
  426.     theWindow := FrontWindow;
  427.     while (theWindow <> NIL) and quitting do
  428.         begin
  429.         quitting := MyDisposeViewerWindow(theWindow) = noErr;
  430.         if quitting then
  431.             theWindow := FrontWindow;
  432.         end;
  433.     { if we closed everything up successfully, we can return noErr, otherwise }
  434.     { indicate to sender of the 'quit' aevt that we canceled }
  435.     if quitting then
  436.         begin
  437.         gQuitFlag := true;                    { user didn't cancel }
  438.          if AEDisposeDesc(gSelfAddress) = noErr then; { Dispose of my self-addressed descriptor }
  439.          end
  440.     else 
  441.         err := userCanceledErr;
  442.     MyAEHandleQUIT := err;
  443.     end;
  444.  
  445. Procedure RegisterMyEvents;
  446.  
  447. Var
  448.     err:    OSErr;
  449.     
  450.     begin
  451.     if not SupportsAEVT then
  452.         exit(RegisterMyEvents);
  453.     err := AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,
  454.         NewAEEventHandlerProc(MyAEHandleOAPP),0,false);
  455.     if err <> noErr then
  456.         exit(RegisterMyEvents);
  457.     err := AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,
  458.         NewAEEventHandlerProc(MyAEHandleODOC),0,false);
  459.     if err <> noErr then
  460.         exit(RegisterMyEvents);
  461.     err := AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,
  462.         NewAEEventHandlerProc(MyAEHandlePDOC),0,false);
  463.     if err <> noErr then
  464.         exit(RegisterMyEvents);
  465.     err := AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,
  466.         NewAEEventHandlerProc(MyAEHandleQUIT),0,false);
  467.     end;
  468.  
  469. Procedure MySendQuitApp;
  470.  
  471. Var
  472.     myAppleEvent, reply:     AppleEvent;
  473.     
  474.     begin
  475.     {    Create the Apple Event. }
  476.     FailIfErr(AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, gSelfAddress,
  477.         kAutoGenerateReturnID, kAnyTransactionID, myAppleEvent));
  478.     {    Send the Apple Event. }
  479.       FailIfErr(AESend(myAppleEvent, reply, kAENoReply+kAENeverInteract, 
  480.           kAENormalPriority, kAEDefaultTimeout, nil, nil));
  481.       if AEDisposeDesc(myAppleEvent) = noErr then;    { Dispose of the Apple Event. }
  482.     end; { of MySendQuitApp }
  483.  
  484. Procedure MySendOpenDoc(myFSSpec: FSSpec);
  485.  
  486. Var
  487.      myAppleEvent:    AppleEvent;
  488.     defReply:        AppleEvent;
  489.     docList:        AEDescList;
  490.     myErr:            OSErr;
  491.     ignoreErr:        OSErr;
  492.     
  493.     begin
  494.     myAppleEvent.dataHandle := nil;
  495.     docList.dataHandle  := nil;
  496.     defReply.dataHandle := nil;
  497.     { Create empty list and add one file spec }
  498.     FailIfErr(AECreateList(nil,0,false, docList));
  499.     FailIfErr(AEPutPtr(docList,1,typeFSS,@myFSSpec,sizeof(FSSpec)));
  500.     FailIfErr(AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments,
  501.         gSelfAddress, kAutoGenerateReturnID, kAnyTransactionID, myAppleEvent));
  502.     { Put Params into our event and send it }
  503.     FailIfErr(AEPutParamDesc(myAppleEvent, keyDirectObject, docList));
  504.     FailIfErr(AESend(myAppleEvent, defReply, kAENoReply+kAENeverInteract,
  505.         kAENormalPriority, kAEDefaultTimeout, nil, nil));
  506.     if myAppleEvent.dataHandle <> nil then
  507.         ignoreErr := AEDisposeDesc(myAppleEvent);
  508.     if docList.dataHandle <> nil then 
  509.         ignoreErr := AEDisposeDesc(docList);
  510.     end; { of MySendOpenDoc }
  511.  
  512. Procedure HandleMenuCommand(menuResult: longint);
  513.  
  514. Var
  515.     menuID:        integer;
  516.     menuItem:    integer;
  517.     daName:        Str255;
  518.     numTypes:    integer;
  519.     myTypes:    array[1..2] of OSType;
  520.     err:        OSErr;
  521.     theRef:        integer;
  522.     myData:        ViewerDataHandle;
  523.     theViewer:    TQ3ViewerObject;
  524.     theWindow:    WindowPtr;
  525.     savedPort:    GrafPtr;
  526.     theFile:    FSSpec;
  527.     theSFReply:    StandardFileReply;
  528.     
  529.     begin
  530.     myTypes[1] := '3DMF';
  531.     myTypes[2] := 'TEXT';
  532.     numTypes := 2;
  533.     menuID := HiWrd(menuResult);
  534.     menuItem := LoWrd(menuResult);
  535.     Case menuID of
  536.         mApple:    case menuItem of
  537.                 iAbout:        HandleAboutApp ;    
  538.                 otherwise    begin
  539.                             GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
  540.                             if OpenDeskAcc(daName) = noErr then;
  541.                             end;
  542.                 {case}        end;
  543.         mFile:    case menuItem of
  544.                 iNew:        theWindow := WindowPtr(MyCreateViewerWindow);
  545.                 iOpen:        begin
  546.                             { Get the file name to open }
  547.                             StandardGetFile( nil, numTypes, @myTypes, theSFReply);
  548.                             { did the user cancel, if not open the file? }
  549.                             if theSFReply.sfGood then
  550.                                 MySendOpenDoc(theSFReply.sfFile);
  551.                             end;
  552.                 iRevert:    begin 
  553.                             { we know this cant be called as longint as there }
  554.                             { is an app window open (MyAdjustMenus) so get the refcon }
  555.                             { from the front window and get the FSSpec from that }
  556.                             theWindow := FrontWindow;
  557.                             myData := ViewerDataHandle(GetWRefCon(theWindow));
  558.                             theFile := myData^^.theFile;
  559.                             { open the file and read it back into the viewer }
  560.                             err := FSpOpenDF(theFile,fsRdPerm,theRef);
  561.                             if err = noErr then
  562.                                 begin
  563.                                 theViewer := myData^^.theViewer;
  564.                                 if Q3ViewerUseFile(theViewer, theRef) = noErr then;
  565.                                 err := FSClose(theRef) ;
  566.                                 end;
  567.                             GetPort(savedPort);
  568.                             SetPort(GrafPtr(theWindow));
  569.                             InvalRect(theWindow^.portRect);
  570.                             SetPort(savedPort);
  571.                             end;    
  572.                 iSave:        begin            
  573.                             { we know this cant be called as longint as there }
  574.                             { is an app window open (MyAdjustMenus) so get the refcon }
  575.                             { from the front window and get the FSSpec from that }
  576.                             theWindow := FrontWindow;
  577.                             myData := ViewerDataHandle(GetWRefCon(theWindow));
  578.                             theFile := myData^^.theFile;
  579.                             theViewer := myData^^.theViewer ;
  580.                             { assumes the original file still exists }
  581.                             err := FSpOpenDF(theFile,fsWrPerm,theRef);
  582.                             if err = noErr then
  583.                                 begin
  584.                                 if Q3ViewerWriteFile(theViewer, theRef) = noErr then;
  585.                                 err := FSClose(theRef);
  586.                                 end;
  587.                             end;
  588.                 iSaveAs:    begin
  589.                             { we know this cant be called as longint as there }
  590.                             { is an app window open (MyAdjustMenus) so get the refcon }
  591.                             { from the front window and get the FSSpec from that }
  592.                             theWindow := FrontWindow;
  593.                             myData := ViewerDataHandle(GetWRefCon(theWindow));
  594.                             theViewer := myData^^.theViewer;
  595.                             StandardPutFile('Save model as:', 'Untitled', theSFReply);
  596.                             if theSFReply.sfGood then
  597.                                 begin
  598.                                 err := FSpOpenDF(theSFReply.sfFile,fsWrPerm,theRef);
  599.                                 if err <> noErr then
  600.                                     begin
  601.                                     err := FSpCreate(theSFReply.sfFile, '????', '3DMF', 
  602.                                         theSFReply.sfScript);
  603.                                     if err = noErr then
  604.                                         err := FSpOpenDF(theSFReply.sfFile, fsCurPerm, theRef);
  605.                                     end;
  606.                                 if err = noErr then
  607.                                     begin
  608.                                     if Q3ViewerWriteFile(theViewer, theRef) = noErr then;
  609.                                     err := FSClose(theRef);
  610.                                     end;
  611.                                 { set up our record of the file location, }
  612.                                 { update the structure }
  613.                                 theWindow := FrontWindow ;
  614.                                 myData := ViewerDataHandle(GetWRefCon(theWindow));
  615.                                 theViewer := myData^^.theViewer ;
  616.                                 myData^^.theFile := theSFReply.sfFile;
  617.                                 myData^^.isFileValid := true;
  618.                                 { reset the window title }
  619.                                 SetWTitle(theWindow, theSFReply.sfFile.name);
  620.                                 end;
  621.                             end;                
  622.                 iClose:        if MyDisposeViewerWindow(FrontWindow) = noErr then;
  623.                 iQuit:        MySendQuitApp;
  624.                 {case}        end;
  625.         mEdit:    begin
  626.                 theWindow := FrontWindow;
  627.                 myData := ViewerDataHandle(GetWRefCon(theWindow));
  628.                 theViewer := myData^^.theViewer;
  629.                 case menuItem of
  630.                     iCut:    if Q3ViewerCut(theViewer) = noErr then;
  631.                     iCopy:    if Q3ViewerCopy(theViewer) = noErr then;
  632.                     iPaste:    if Q3ViewerPaste(theViewer) = noErr then;
  633.                     iClear:    if Q3ViewerClear(theViewer) = noErr then;
  634.                     otherwise;
  635.                 {case}        end;
  636.                 end; 
  637.     {Case}        end;
  638.     HiliteMenu(0);    { Unhighlight whatever MenuSelect or MenuKey hilited }
  639.     end;
  640.  
  641. Procedure HandleKeyPress(event: EventRecord);
  642.  
  643. Var
  644.     key:    char;
  645.  
  646.     begin
  647.     key := chr(BAnd(event.message,charCodeMask));
  648.     { just check to see if we want to quit... }
  649.     if BAnd(event.modifiers,cmdKey) > 0 then  { Command key down? }
  650.         HandleMenuCommand(MenuKey(key));
  651.     end;
  652.  
  653. Function HandleEvent(theEvent: EventRecord): boolean;
  654.  
  655. Var
  656.     thePart:        integer;
  657.     theWindow:        WindowPtr;
  658.     screenRect:        Rect;
  659.     oldPort:        GrafPtr;
  660.     aPoint:            Point;
  661.     theViewer:        TQ3ViewerObject;
  662.     myData:            ViewerDataHandle;
  663.     
  664.     begin
  665.     setPt(aPoint,100,100);
  666.     case theEvent.what of
  667.         mouseDown:
  668.             begin
  669.             thePart := FindWindow(theEvent.where, theWindow);
  670.             case thePart of
  671.                 inMenuBar:    begin
  672.                             MyAdjustMenus;
  673.                             HandleMenuCommand(MenuSelect(theEvent.where));
  674.                             end;
  675.                 inDrag:        begin
  676.                             screenRect := GetGrayRgn^^.rgnBBox;
  677.                             DragWindow(theWindow,theEvent.where,screenRect);
  678.                             end;
  679.                 inContent:    if theWindow <> FrontWindow then
  680.                                 SelectWindow(theWindow);
  681.                 inGoAway:    if TrackGoAway(theWindow, theEvent.where) then
  682.                                 if MyDisposeViewerWindow(theWindow) = noErr then;
  683.                 otherwise;    
  684.             {case}            end;
  685.             end;
  686.         updateEvt:
  687.             begin
  688.             theWindow := WindowPtr(theEvent.message);
  689.             myData := ViewerDataHandle(GetWRefCon(theWindow));
  690.             theViewer := myData^^.theViewer;
  691.             GetPort(oldPort);    
  692.             SetPort(theWindow);
  693.             BeginUpdate(theWindow);
  694.             if Q3ViewerDraw(theViewer) = noErr then;
  695.             EndUpdate(theWindow);
  696.             SetPort(oldPort);
  697.             end;
  698.         keyDown, autoKey:
  699.             HandleKeyPress(theEvent);
  700.         diskEvt:
  701.             if HiWrd(theEvent.message) <> noErr then
  702.                 if DIBadMount(aPoint, theEvent.message) = noErr then;
  703.         osEvt:    { does nothing }
  704.             ;
  705.         activateEvt:
  706.             begin
  707.             theWindow := WindowPtr(theEvent.message);
  708.             if theWindow <> nil then
  709.                 HandleActivateWindow(theWindow,BAnd(theEvent.modifiers,activeFlag));
  710.             end;
  711.         kHighLevelEvent:    { Let the Apple Event Manager handle high level event. }
  712.             if AEProcessAppleEvent(theEvent) = noErr then;
  713.     {case}    end;
  714.     HandleEvent := true;
  715.     end;
  716.  
  717. Procedure MainEventLoop;
  718.  
  719. Var
  720.     event:                EventRecord;
  721.     theWindow:            WindowPtr;
  722.     wasViewerEvent:        Boolean;
  723.     savedPort:            GrafPtr;
  724.     localPt:            Point;
  725.     theViewer:            TQ3ViewerObject;
  726.     myData:                ViewerDataHandle;
  727.  
  728.     begin
  729.     MyAdjustMenus;
  730.     while not gQuitFlag do
  731.         begin
  732.         if WaitNextEvent(everyEvent,event,0,nil) then
  733.             begin
  734.             theWindow := FrontWindow;
  735.             if theWindow <> nil then
  736.                 begin
  737.                 myData := ViewerDataHandle(GetWRefCon(theWindow));
  738.                 theViewer := myData^^.theViewer;
  739.                 end;
  740.             if theViewer <> nil then
  741.                 begin
  742.                 GetPort(savedPort);
  743.                 SetPort(GrafPtr(theWindow));
  744.                 GetMouse(localPt);
  745.                 if not Q3ViewerAdjustCursor(theViewer,localPt) then
  746.                     InitCursor;
  747.                 wasViewerEvent := Q3ViewerEvent(theViewer,event);
  748.                 SetPort(savedPort);
  749.                 end
  750.             else
  751.                 wasViewerEvent := false;
  752.             if not wasViewerEvent then
  753.                 if HandleEvent(event) then;
  754.             end;
  755.         end;
  756.     end;
  757.  
  758. Procedure Initialize;
  759.  
  760. Var
  761.     menuBar:    Handle;
  762.  
  763.     begin
  764.     InitGraf(@qd.thePort);
  765.     InitFonts;
  766.     InitWindows;
  767.     InitMenus;
  768.     TEInit;
  769.     InitDialogs(nil);
  770.     InitCursor;
  771.     gQuitFlag := false;
  772.     SetPt(gStaggerPos,50,50);
  773.     with kRGBBlack do
  774.         begin
  775.         red := 0; green := 0; blue := 0;
  776.         end;
  777.     with kRGBWhite do
  778.         begin
  779.         red := $FFFF; green := $FFFF; blue := $FFFF;
  780.         end;
  781.     menuBar := GetNewMBar(128);                { Read menus into menu bar, MBAR res id is 128 }
  782.     if menuBar = nil then
  783.          ExitToShell;                        { if we dont have it then quit - your app  }
  784.     SetMenuBar(menuBar);                    { Install menus }
  785.     DisposeHandle(menuBar);
  786.     AppendResMenu(GetMenuHandle(mApple), 'DRVR');    { Add DA names to Apple menu, ID 128 }
  787.     MyAdjustMenus;
  788.     DrawMenuBar;
  789.     end;
  790.  
  791. Var
  792.     theString: Str255;
  793.  
  794. Begin
  795. MoreMasters; 
  796. MoreMasters; 
  797. MoreMasters;
  798. MaxApplZone;    { Maximize the heap - the viewer requires at least 32k }
  799. Initialize;
  800. {
  801.     WE DON'T CHECK FOR 68K machine.
  802.     Instead I use the NotPPC.rsrc resource file.  This is a file with a 68k CODE 0
  803.     and CODE 1 resource that puts up a dialog that says "this app only runs on a power
  804.     macintosh computer.
  805. }
  806. if SupportsAEVT and SupportsQuickDraw3D and SupportsQuickDraw3DViewer then
  807.     begin
  808.     { AppleEvent stuff: }
  809.     { Set up the self-addressed descriptor record. }
  810.      gSelfPSN.highLongOfPSN := 0;
  811.      gSelfPSN.lowLongOfPSN := kCurrentProcess; { Use this instead of GetCurrentProcess }
  812.      FailIfErr(AECreateDesc(typeProcessSerialNumber,@gSelfPSN,sizeof(ProcessSerialNumber),
  813.          gSelfAddress));
  814.     RegisterMyEvents;    { register the appleevents for this app }
  815.     MainEventLoop;        { Handle events 'til we die }
  816.     end 
  817. else 
  818.     begin
  819.     GetIndString(theString,kQD3DAlertID,3);
  820.     ParamText(theString, '', '', '');
  821.     if Alert(kQD3DAlertID, nil) = noErr then;
  822.     end
  823. end.
  824.